home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************/
- /* */
- /* CTreeViewer */
- /* */
- /* This program graphs the visual hierarchy and the chain of command. To use */
- /* it, include the class into your project, and call ITreeViewer in your */
- /* application's initialization method. Then call one of the three viewing */
- /* methods described below. */
- /* */
- /* ITreeViewer (short WINDid, Boolean floating, CDesktop *anEnclosure, */
- /* CDirectorOwner *aSupervisor) */
- /* If WINDid != 0, the window is read from a WIND resource. The window */
- /* should not have a close box. */
- /* */
- /* ShowSubviews (CView *theView) */
- /* This shows the subviews enclosed by theView, in the form of a tree. */
- /* */
- /* ShowEnclosures (CView *theView) */
- /* This shows all the views that enclose theView. */
- /* */
- /* ShowSupervisors (CBureaucrat *theBureaucrat) */
- /* This shows the chain of command starting from theBureaucrat and */
- /* working upward. */
- /* */
- /******************************************************************************/
-
- #include "CTreeViewer.h"
- #include <CBartender.h>
- #include <CBureaucrat.h>
- #include <CClipboard.h>
- #include <CDirectorOwner.h>
- #include <CDesktop.h>
- #include <CList.h>
- #include <CPicture.h>
- #include <CScrollPane.h>
- #include <CView.h>
- #include <CWindow.h>
- #include <Commands.h>
- #include <TBUtilities.h>
-
- extern CDesktop *gDesktop;
- extern CBartender *gBartender;
- extern CClipboard *gClipboard;
-
- //
- // ITreeViewer
- //
- // Initialize the instance of this class. If WINDid == 0, it creates its own,
- // otherwise it reads the window from a resource with ID WINDid. The other
- // inputs are the same as for CWIndow::IWindow.
- //
-
- void CTreeViewer :: ITreeViewer (short WINDid,
- Boolean floating,
- CDesktop *anEnclosure,
- CDirectorOwner *aSupervisor)
- {
- PicHandle aPicture;
- Rect theRect;
- long itsID;
- //
- // Initialize this director by calling its superclass' initialization
- //
- CDirector::IDirector (aSupervisor);
- //
- // Create a window for this
- //
- itsWindow = new CWindow;
- if (WINDid != 0)
- {
- itsWindow->IWindow(WINDid, floating, anEnclosure, this);
- itsID = WINDid;
- }
- else
- {
- Rect theRect = {100, 100, 200, 400};
-
- itsWindow->INewWindow (&theRect, true, zoomDocProc, floating, false,
- anEnclosure, this);
- itsWindow->SetTitle("\pTree Viewer");
- itsID = 'Tree';
- }
- itsWindow->SetID (itsID);
- //
- // Create a new scrollpane and install it in this window
- //
- itsScrollPane = new CScrollPane;
- itsScrollPane->IScrollPane (itsWindow, this, 0, 0, 0, 0, sizELASTIC,
- sizELASTIC, true, true, true);
- itsScrollPane->FitToEnclFrame (true, true);
- itsScrollPane->SetSteps (kSVCellDepth, kSVCellWidth);
- itsScrollPane->SetID (itsID);
- //
- // Create a CPicture and install it in the scrollpane. For the moment, it is
- // empty
- //
- itsPicture = new CPicture;
- itsPicture->IPicture (itsScrollPane, this, 0, 0, 0, 0, sizELASTIC,
- sizELASTIC);
- itsPicture->FitToEnclosure (true, true);
- itsScrollPane->InstallPanorama(itsPicture);
- }
-
-
-
- //
- // ShowSubviews
- //
- // This method draws the subviews of the given view in tree form.
- //
-
- void CTreeViewer :: ShowSubviews (CView *theView)
- {
- short width, depth, hSize, vSize;
- PicHandle thePicH;
- Rect theRect;
- GrafPort myPort;
- GrafPtr oldPort, myPortPtr = &myPort;
-
- //
- // Take the old picture (if any) and get rid of it
- //
- thePicH = itsPicture->GetMacPicture();
- if (thePicH) KillPicture (thePicH);
-
- //
- // Call GetSizeSV will get the size of the resulting picture in units of cells
- // (depth cells deep and width cells wide). Each cell occupies kSVCellDepth
- // pixels horizontally and kSVCellWidth vertically.
- //
- depth = 0;
- GetSizeSV (theView, &width, &depth, 0);
- hSize = kSVCellDepth * depth;
- vSize = kSVCellWidth * width;
-
- //
- // Here we create the picture that we will install in the panorama. We start
- // by creating our own GrafPort which we will draw into. Creating our own
- // GrafPort allows us to fiddle with the text font and size, as well as adjust
- // the clip region (necessary for the OpenPicture to work right)
- //
- SetRect (&theRect, 0, 0, hSize, vSize);
- GetPort (&oldPort);
- OpenPort (myPortPtr);
- SetPort (myPortPtr);
- TextFont (1);
- TextSize (9);
- // ClipRect (&thePort->portRect);
- ClipRect (&theRect);
- thePicH = OpenPicture (&theRect);
- DrawTreeSV (theView, 1, vSize/2, width, true);
- ClosePicture ();
- SetPort (oldPort);
- ClosePort (myPortPtr);
- //
- // Now install this picture
- //
- InstallPicture (thePicH, hSize, vSize);
- }
-
-
- //
- // GetSizeSV
- //
- // This method finds the width and depth of the subview tree starting at
- // theView. It calls itself recursively to search the tree.
- //
- // Input: theView - the view at the top of this branch of the tree
- // thisDepth - the depth of this node in the tree
- // *depth_p - the maximum depth found so far
- // Output: width - the width of this branch of the tree
- // *depth_p - the maximum depth found so far
-
- void CTreeViewer :: GetSizeSV (CView *theView, short *width, short *depth_p,
- short thisDepth)
- {
- CList *theList;
- CView *itsSubview;
- short itsWidth, sum;
- long i, n;
-
- thisDepth += 1;
- if (thisDepth > *depth_p) *depth_p = thisDepth;
- if (theView == gDesktop)
- {
- theList = gDesktop->itsWindows;
- }
- else
- {
- theList = theView->itsSubviews;
- }
- if (theList)
- {
- n = theList->GetNumItems();
- sum = 0;
- for (i=1; i<=n; i++)
- {
- itsSubview = (CView *)theList->NthItem(i);
- GetSizeSV (itsSubview, &itsWidth, depth_p, thisDepth);
- sum += itsWidth;
- }
- }
- else
- {
- sum = 1;
- }
- *width = sum;
- }
-
-
- //
- // DrawTreeSV
- //
- // This method does the actual drawing of the tree.
- //
- // Input: theView - the view at the top of this branch of the tree
- // h, v - the point at which to start drawing (window coordinates)
- // myWidth - the width of this branch
- // first - controls whether to draw a stem
-
- void CTreeViewer :: DrawTreeSV (CView *theView, short h, short v,
- short myWidth, Boolean first)
- {
- Str63 name, ID;
- Rect theRect;
- short textw, temp, itsWidth, sum, itsv;
- long i, n;
- CList *theList;
- CView *itsSubview;
-
- //
- // Draw the stem
- //
- if (!first)
- {
- MoveTo (h, v);
- h += 4;
- LineTo (h, v);
- }
-
- SetRect (&theRect, h, v-kSVBoxHeight/2, h+kSVBoxWidth, v+kSVBoxHeight/2);
- //
- // Draw a gray box if it invisible, with a thick line if it is active, and make
- // it a rounded rectangle if the view doesn't want mouse clicks
- //
- if (theView->ReallyVisible())
- PenPat (black);
- else
- PenPat (gray);
-
- if (theView->IsActive())
- PenSize (2,2);
- else
- PenSize (1,1);
-
- if (theView->GetWantsClicks())
- FrameRect (&theRect);
- else
- FrameRoundRect (&theRect, 12, 12);
- PenPat (black);
- PenSize (1,1);
-
- //
- // Get the name of the class, and the ID. If the ID is a resource number,
- // convert it to a string; if it is a 4-character name, get it.
- //
- theView->GetClassName(name);
- i = theView->GetID();
- if ((i < 0 && i >= -32768) || (i > 0 && i <= 32767))
- {
- NumToString (i, ID);
- ConcatPStrings (name, "\p ");
- ConcatPStrings (name, ID);
- }
- if (LongToStr(i, ID))
- {
- ConcatPStrings (name, ID);
- }
- textw = StringWidth (name);
- MoveTo (h + kSVBoxWidth/2 - textw/2, v+3);
- DrawString (name);
- //
- // Now get the list of views enclosed by this view
- //
- if (theView == gDesktop)
- {
- theList = gDesktop->itsWindows;
- }
- else
- {
- theList = theView->itsSubviews;
- }
-
- if (theList)
- {
- n = theList->GetNumItems();
- //
- // Draw the stem
- //
- h += kSVBoxWidth;
- MoveTo (h,v);
- h += 4;
- LineTo (h,v);
- if (n == 1)
- {
- itsSubview = (CView *)theList->FirstItem();
- DrawTreeSV (itsSubview, h, v, myWidth, false);
- }
- else
- {
- sum = 0;
- for (i=1; i<=n; i++)
- {
- itsSubview = (CView *)theList->NthItem(i);
- GetSizeSV (itsSubview, &itsWidth, &temp, 0);
- itsv = v + kSVCellWidth * sum + (kSVCellWidth/2) * (itsWidth - myWidth);
- //
- // Draw the branch
- //
- if (i == 1 || i == n)
- {
- MoveTo (h, v);
- LineTo (h, itsv);
- }
- //
- // Call this method recursively to draw the subviews of this view
- //
- DrawTreeSV (itsSubview, h, itsv, itsWidth, false);
- sum += itsWidth;
- }
- }
- }
- }
-
-
-
- //
- // ShowEnclosures
- //
- // This method draws the enclosures of this view. This method is almost
- // identical to ShowSubviews: see that method for comments
- //
-
- void CTreeViewer :: ShowEnclosures (CView *theView)
- {
- short height, hSize, vSize;
- PicHandle thePicH;
- Rect theRect;
- GrafPort myPort;
- GrafPtr oldPort, myPortPtr = &myPort;
-
- thePicH = itsPicture->GetMacPicture();
- if (thePicH) KillPicture (thePicH);
-
- height = 0;
- GetSizeE (theView, &height);
- hSize = kECellWidth;
- vSize = kECellHeight * height;
-
- SetRect (&theRect, 0, 0, hSize, vSize);
- GetPort (&oldPort);
- OpenPort (myPortPtr);
- SetPort (myPortPtr);
- TextFont (1);
- TextSize (9);
- ClipRect (&theRect);
- thePicH = OpenPicture (&theRect);
- DrawHierE (theView, hSize/2, vSize, true);
- ClosePicture ();
- SetPort (oldPort);
- ClosePort (myPortPtr);
-
- InstallPicture (thePicH, hSize, vSize);
- }
-
-
- //
- // GetSizeE
- //
- // This method finds the number of enclosures (height) surrounding theView, up
- // to the gDesktop.
- //
-
- void CTreeViewer :: GetSizeE (CView *theView, short *height_p)
- {
- CView *itsEnclosure;
-
- *height_p += 1;
- itsEnclosure = theView->itsEnclosure;
- if (itsEnclosure) GetSizeE (itsEnclosure, height_p);
- }
-
-
- //
- // DrawHierE
- //
- // This method draws the hierarchy of enclosures.
- //
- // Input: theView - the view at the top of this branch of the tree
- // h, v - the point at which to start drawing (window coordinates)
- // first - controls whether to draw a stem
-
- void CTreeViewer :: DrawHierE (CView *theView, short h, short v, Boolean first)
- {
- Str63 name, ID;
- Rect theRect;
- short textw;
- long i;
- CView *itsEnclosure;
-
- if (!first)
- {
- MoveTo (h, v);
- v -= 4;
- LineTo (h, v);
- }
- SetRect (&theRect, h-kEBoxWidth/2, v-kEBoxHeight, h+kEBoxWidth/2, v);
- //
- // Draw a gray box if it invisible, with a thick line if it is active, and make
- // it a rounded rectangle if the view doesn't want mouse clicks
- //
- if (theView->ReallyVisible())
- PenPat (black);
- else
- PenPat (gray);
- if (theView->IsActive())
- PenSize (2,2);
- else
- PenSize (1,1);
- if (theView->GetWantsClicks())
- FrameRect (&theRect);
- else
- FrameRoundRect (&theRect, 12, 12);
- PenPat (black);
- PenSize (1,1);
-
- theView->GetClassName(name);
- i = theView->GetID();
- if ((i < 0 && i >= -32768) || (i > 0 && i <= 32767))
- {
- NumToString (i, ID);
- ConcatPStrings (name, "\p ");
- ConcatPStrings (name, ID);
- }
- if (LongToStr(i, ID))
- {
- ConcatPStrings (name, ID);
- }
- textw = StringWidth (name);
- MoveTo (h - textw/2, v-5);
- DrawString (name);
- //
- // If this view has an enclosure, call this method recursively to draw it.
- //
- itsEnclosure = theView->itsEnclosure;
- if (itsEnclosure) DrawHierE (itsEnclosure, h, v-kEBoxHeight, false);
- }
-
-
-
- //
- // ShowSupervisors
- //
- // This method draws the supervisors of this bureaucrat. This method is almost
- // identical to ShowSubviews: see that method for comments
- //
-
- void CTreeViewer :: ShowSupervisors (CBureaucrat *theBureaucrat)
- {
- short height, hSize, vSize;
- PicHandle thePicH;
- Rect theRect;
- GrafPort myPort;
- GrafPtr oldPort, myPortPtr = &myPort;
-
- thePicH = itsPicture->GetMacPicture();
- if (thePicH) KillPicture (thePicH);
-
- height = 0;
- GetSizeS (theBureaucrat, &height);
- hSize = kECellWidth;
- vSize = kECellHeight * height;
-
- SetRect (&theRect, 0, 0, hSize, vSize);
- GetPort (&oldPort);
- OpenPort (myPortPtr);
- SetPort (myPortPtr);
- TextFont (1);
- TextSize (9);
- ClipRect (&theRect);
- thePicH = OpenPicture (&theRect);
- DrawHierS (theBureaucrat, hSize/2, vSize, true);
- ClosePicture ();
- SetPort (oldPort);
- ClosePort (myPortPtr);
-
- InstallPicture (thePicH, hSize, vSize);
- }
-
-
- //
- // GetSizeS
- //
- // This method finds the number of bureaucrats (height) which supervise
- // theBureaucrat, up to the gApplication
- //
-
- void CTreeViewer :: GetSizeS (CBureaucrat *theBureaucrat, short *height_p)
- {
- CBureaucrat *itsSupervisor;
-
- *height_p += 1;
- itsSupervisor = theBureaucrat->itsSupervisor;
- if (itsSupervisor) GetSizeS (itsSupervisor, height_p);
- }
-
-
- //
- // DrawHierS
- //
- // This method draws the hierarchy of supervisors.
- //
- // Input: theBureaucrat - the view at the top of this branch of the tree
- // h, v - the point at which to start drawing
- // first - controls whether to draw a stem
-
- void CTreeViewer :: DrawHierS (CBureaucrat *theBureaucrat, short h, short v, Boolean first)
- {
- Str63 name, ID;
- Rect theRect;
- short textw;
- long i;
- CBureaucrat *itsSupervisor;
-
- if (!first)
- {
- MoveTo (h, v);
- v -= 4;
- LineTo (h, v);
- }
- SetRect (&theRect, h-kEBoxWidth/2, v-kEBoxHeight, h+kEBoxWidth/2, v);
- if (member(theBureaucrat, CView))
- {
- if (((CView *)theBureaucrat)->CanBeGopher()) PenSize (2,2);
- FrameRect (&theRect);
- }
- else
- {
- PenSize (2,2);
- FrameRoundRect (&theRect, 12, 12);
- }
- PenSize (1,1);
-
- theBureaucrat->GetClassName(name);
- textw = StringWidth (name);
- MoveTo (h - textw/2, v-5);
- DrawString (name);
- //
- // If this bureaucrat has a supervisor, call this method recursively to draw it
- //
- itsSupervisor = theBureaucrat->itsSupervisor;
- if (itsSupervisor) DrawHierS (itsSupervisor, h, v-kEBoxHeight, false);
- }
-
-
- //
- // This method disables closing the window (since the class can't handle it when
- // its window closes), and it enables copying the picture.
- //
-
- void CTreeViewer :: UpdateMenus()
- {
- inherited::UpdateMenus();
- gBartender->DisableCmd(cmdClose);
- gBartender->EnableCmd(cmdCopy);
- }
-
-
- //
- // This method handles copying the picture to the clipboard
- //
-
- void CTreeViewer :: DoCommand(long theCommand)
- {
- switch (theCommand)
- {
- case cmdCopy:
- gClipboard->EmptyScrap();
- gClipboard->PutData('PICT',(Handle)itsPicture->GetMacPicture());
- break;
-
- default:
- inherited::DoCommand(theCommand);
- break;
- }
- }
-
-
- //
- // This method installs picture into the scrollpane
- //
-
- void CTreeViewer :: InstallPicture (PicHandle thePict, short hSize, short vSize)
- {
- Rect sizeRect;
- LongRect interior;
- short maxh, maxv;
-
- itsPicture->SetMacPicture (thePict);
- //
- // The following is just to make sure that zooming out will grow the window only as
- // large as the picture.
- //
- itsWindow->GetInterior (&interior);
- maxh = MAX(interior.right, hSize+20);
- maxv = MAX(interior.bottom, vSize+20);
- SetRect (&sizeRect, kSVCellDepth + 20, kSVCellWidth + 20, maxh, maxv);
- itsWindow->SetSizeRect (&sizeRect);
- //
- // Redraw the screen with the new picture
- //
- itsScrollPane->Refresh();
- }
-
-
- //
- // This method decides if num is a 4-character string; if so, it returns the
- // string enclosed in quotes in theType.
- //
-
- Boolean CTreeViewer :: LongToStr (long num, Str63 theType)
- {
- char c1, c2, c3, c4;
-
- c1 = num >> 24;
- if (c1 < ' ' || c1 > 'z') return false;
- c2 = (num >> 16) & 0xFF;
- if (c2 < ' ' || c2 > 'z') return false;
- c3 = (num >> 8) & 0xFF;
- if (c3 < ' ' || c3 > 'z') return false;
- c4 = num & 0xFF;
- if (c4 < ' ' || c4 > 'z') return false;
- theType[0] = 7;
- theType[1] = ' ';
- theType[2] = '\'';
- theType[3] = c1;
- theType[4] = c2;
- theType[5] = c3;
- theType[6] = c4;
- theType[7] = '\'';
- return true;
- }